Welcome back. Let's try querying another rest API,
this one from Flickr,
one of the first popular photo sharing sites.
It's still used by a lot of excellent photographers.
It's run by Yahoo now.
Here's the overview, documentation page for the Flickr API.
We're going to use the photo searching endpoint.
There are lots of other things you can do with
the Flickr rest API including posting photos and lots of other things.
We'll just look at searching because you can do that even if you only
like looking at photographs and you don't have
a Flickr account where you've uploaded photos.
So first, at the bottom of this page,
notice that they give what they call an endpoint.
That's what we will call the base URL.
Everything after that is going to have question mark,
key equals value pairs.
The next notice that they have a required parameter called the api_key.
So one of these is going to have to be api_key equals something.
That's a developer specific key that you get from Flickr by signing up for it.
If you access one of our few cached queries,
you actually won't need an api_key.
But if you want to run any other queries that we haven't put into a cache for you,
you will need to get an api_key from Flickr.
A third thing to notice on this page is that they have
another required query parameter called method.
So we're going to have to have something that says method equals something.
In our case, it's going to be something about
search and we'll find that at a more specific documentation page.
So let's look at the documentation page for searching.
I already have it loaded here.
We're going to have to say method equals flickr.photos.search.
There are also a bunch of other keys that we can provide,
what they call arguments.
I'm just going to clear my marking here,
and scroll down to show you that there's a lot of options or arguments,
and it just keeps going.
These are all things that are going to affect what gets retrieved.
So we can ask for only things that
are photos that are taken indoors or only photos that are taken outdoors.
We can provide a latitude and longitude,
and it'll bring us back photos that are within some radius of that location on Earth.
So there's a bunch of them here.
We're not going to use them all in the examples that I show you,
but we can come back to them whenever we need.
It's worth noting that the api_key is required.
I talked about that already.
Then, we're going to search for tags.
So photos, Flickr, the photographer,
when they upload them, they can give them tags like this is indoors,
or this is still life or this has mountains in it,
or they can put a city name,
any tag that they choose.
So we're going to use that to search for photos of mountains and rivers.
Then, there's this tag_mode.
If you provide more than one tag that can either be treated as you want to
search for photos that have one of those tags as
the or combination or that you want to search for photos that have all of those tags,
that's the and combination.
Now, if I scroll all the way down,
we'll see something about what the results look like.
Here's an example response.
You'll notice that it doesn't look much like our favorite JSON format.
This is actually XML format.
So by default, Flickr returns data not in the JSON format, but in XML.
It's possible to parse XML in Python.
It's not that difficult, but we're not going to go into that in this specialization.
Most sites that provide XML also have some way to ask for JSON instead.
Flickr does have weighed asked for JSON instead.
They don't make it that easy to find out how.
I didn't find it anywhere on this page.
I did do another Google search.
If I just search for Flickr API JSON,
the first response that comes up is
a documentation page about how to get things in JSON format.
Now, the trick is, I'm going to show you somewhere here,
and it's right here, send a parameter called format with a value of JSON.
So we're going to have in our URL format equals JSON.
There's one other little tricky thing.
I'm just going to get rid of those markings,
and we'll scroll down to the bottom of the page,
they have a little thing that says something about callback functions.
It turns out we have to send nojsoncallback equals one.
Now, it's a little more technical than we're ready for,
but here's the basic idea.
Without that nojsoncallback equals one,
you would get JSON results that are wrapped
in basically a JavaScript function invocation called the callback.
So that wrapping is part of a standard called JSONP.
In any case, what we need to do is we need to include nojsoncallback
equals one in order to just get pure JSON without any extra characters around it.
So with that basics from the documentation,
let's look at some code for making API requests.
As with the other APIs,
we're going to use requests with caching,
so that we can avoid you having to actually get an api_key from Flickr.
You'll just get data from our cache where we won't check for needing an api_key.
Just like we did for the data muse API,
I've defined a function, get_flickr_data.
We'll pass in as a parameter as
tags_string that's saying what tags we want to search for.
So when I call it on line 26,
I'm going to pass in this comma separated list of tags, river, mountains.
Inside this get_flickr_data function,
you can see that I'm going to get set up to make a call to the request with caching.get.
In order to set up for that, I set my base URL,
and make an empty parameters dictionary,
and then I set a bunch of key value pairs.
I'm going to add API key equals whatever I have for my Flickr_key,
which is just a variable up here.
For the tags key,
I'm going to set it to be river,
mountains or whatever the current value of tags string is,
whatever has been passed in to this function.
For the tag mode, I'm going to say all.
I want photos that have both river and mountains as a tag.
The method is flickr.photos.search.
I only want to get five results back.
I would like only photos not videos and I want
the format to be JSON and no JSON callback equals one.
So, that creates that whole dictionary,
I pass that in to my request.get or requests with caching.get and
I'm telling the request with caching to use
the file called Flickrcache.text as it's caching file.
So, I get a response object back and I'm just going to print the URL from that.
That's the URL that we would have gone to if we didn't find it in the cache,
and then we return a Python object.
We turn the text string into either a list or a dictionary by calling this.JSON method.
So, I'm going to invoke that on line 26 and then,
once I get the results back as a Python object,
in this case, it's going to be a dictionary,
I have to go through my understand, extract,
repeat process to figure out how to pull out the data that I want.
Again, I've already done that so I'm not going to walk you through that process but I've
discovered that the result dictionary has a top-level key called photos.
As the value associated with the photos key,
there's another dictionary, and that dictionary has a key called photo.
I find that a little confusing,
but that's the way the data comes back from Flickr.
The value associated with that photo key is a list.
It's a list of dictionaries,
one dictionary for each photograph.
The dictionary for one photograph has a key called owner and another key called ID.
So, for each of the photo dictionaries that's returned,
I'm going to extract the owner and the photo ID.
I can stick those two values into a URL because I've looked up
what is the format that Flickr uses for making URLs
to actually load a page with a single photo in it,
and I am just substituting owner and photo ID in to make this URL string.
So, if I run this I'm going to get a printout of five different URLs.
You can see the five URLs are here and above it,
we got the URL that we would have fetched if we hadn't found the result in the cache.
If this were a full Python environment,
we would be able to import the web browser module,
and we could call webbrowser.open,
which would make this URL open up automatically in another tab.
I don't have that option available to me,
so I'm just going to,
we printed it out, and I'll go and make a new tab.
We will visit that URL,
and there we have a photo that's tagged with mountains and river.
I can see the river, I'm not quite sure where the mountain is for this one.
We got some more. Here's another one.
I put that URL in instead.
Here's one that does have a river and a mountain.
Now, notice that on line 23 I have the code printing out the URL.
That's the URL that we would have visited if we hadn't found it in the cache.
If I copy this,
I can go to another tab and see what I
would get if I actually went to that URL for the API call.
The answer is I get a message saying,
we failed because it's an invalid API key.
So, I didn't provide a valid API key and so,
I can't actually make that query.
That's one of the advantages of getting the stuff from the cache is
that we're not requiring you to have that API key.
Now, if I were to change this and instead of asking for say, river and mountains,
ask for cows and mountains,
I've tried this before and we tend to get
beautiful pictures from Switzerland and the Pyrenees in Europe.
If I try to do this,
it won't find it in that cache,
and so it will try to fetch it.
So, it's new and adding it to the cache.
Here's what the URL is,
but we get an error,
and the error is on line 30.
When we go to try to extract the photos and photo IDs on line 30,
we're finding that we get a key error.
In the dictionary of results,
we don't have anything called photos.
So, let's see what
the result really was
and it's going to be the same error message that we saw in the browser window.
We get the error message that it was an invalid API key.
So, you can make this work if you sign up for
an API key and put your API key on line eight,
you would be able to make new queries with this code.
We didn't show it here, but there are other operations with Flickr
that require user specific authentication.
If you want to post photos to somebody's account,
you'd need to prove that you have permission from them.
APIs provide features for doing that kind of
user authorization through a protocol called OAuth,
but that's beyond the scope of this specialization.
Once you've authorized, each request would get digitally
signed and Python provides a module for doing that called, requests with OAuth.
Again, it's beyond the scope of this specialization.
The key takeaways from this lesson.
One, sometimes you need to pass a lot of query parameters.
Take a look at lines 13 through 20.
Sometimes there are a lot of choices about what the query parameters are,
remember that long list in the documentation.
Sometimes you have to specify that you want things in
JSON format because that might not be the default.
Sometimes you have to specify other idiosyncratic things
like this no JSON callback equals one query parameter.
Finally, many sites require you to provide
an API key which you get by registering with that site. See you next time.